﻿#pragma once

#include "../Utils/HCNMath.h"
#include "../Utils/Utils.h"

#include "TextHolder.h"
#include "CEntity.h"
#include "CItem.h"

//#include "Tag.h"

class C_Material {
public:
	int32_t type{};  // 5 for water, 6 for lava
	bool isFlammable{};
	bool isNeverBuildable{};
	bool isAlwaysDestroyable{};
	bool isReplaceable{};
	bool isLiquid{};  // 0x0008
private:
	[[maybe_unused]] uint8_t pad2[0x3]{};  // 0x009
public:
	float translucency{};  // 0x00C
	bool isBlockingMotion{};
	bool isBlockingPrecipitation{};
	bool isSolid{};
	bool isSuperHot{};
	float color[4]{};
};

class C_Entity;
class C_Block;
class C_BlockSource;
class C_Material;

class C_BlockLegacy {
public:
	uintptr_t **Vtable{};          // 0x0000
	TextHolder tileName {};  // 0x0008
private:
	[[maybe_unused]] uint8_t pad_0028[8]{};  // 0x0028
public:
	TextHolder name {};  // 0x0030
private:
	[[maybe_unused]] uint8_t pad_0050[136]{};  // 0x0050
public:
	C_Material *material{};  // 0x00D8
private:
	[[maybe_unused]] uint8_t pad_00E0[108]{};  // 0x00E0
public:
	int16_t blockId{};  // 0x014C

public:
	// int liquidGetDepth(C_BlockSource*, const vec3_ti* pos);
	void liquidGetFlow(vec3_t &flowOut, C_BlockSource &, const vec3_ti &pos) const;
	bool getCollisionShape(AABB &collShapeOut, C_Block &block, C_BlockSource &blockSource, const vec3_ti &pos);
	bool hasWater(C_BlockSource &, const vec3_ti &pos) const;
	void setExplodeable(float a2);
};

class C_Block {
public:
	uint8_t data{};  // 0x8

private:
	[[maybe_unused]] uint8_t pad[0x7]{};

public:
	C_BlockLegacy *blockLegacy{};  // 0x10

public:
	inline C_BlockLegacy *toLegacy() { return blockLegacy; }

	virtual ~C_Block();
	virtual class BlockRenderLayer getRenderLayer();

	inline bool operator==(C_Block const &a2) const {
		if (blockLegacy == nullptr || a2.blockLegacy == nullptr)
			return false;
		return blockLegacy == a2.blockLegacy && data == a2.data;
	}

	inline bool operator!=(C_Block const &a2) const {
		if (blockLegacy == nullptr || a2.blockLegacy == nullptr)
			return false;
		return blockLegacy != a2.blockLegacy || data != a2.data;
	}
	/**************************************************************
	 * 尽量不要使用以下函数不知道虚表地址是否正确！！！！！！！！！！！！！
	 *************************************************************/

#if 0
	virtual void addAABBs(C_BlockSource const &, vec3_ti const &, AABB const *, std::vector<AABB> &) const ;
	virtual bool addCollisionShapes(C_BlockSource const &, vec3_ti const &, AABB const *, std::vector<AABB> &, class optional_ref) const ;
	virtual C_Block &addTag(class HashedString const &) ;
	virtual void animateTick(C_BlockSource &, vec3_ti const &, class Random &) const ;
	virtual class ItemInstance asItemInstance(C_BlockSource &, vec3_ti const &) const ;
	virtual bool attack(C_Player *, vec3_ti const &) const ;
	virtual bool breaksFallingBlocks(class BaseGameVersion) const ;
	virtual std::u8string buildDescriptionId() const ;
	virtual std::u8string buildDescriptionName() const ;
	virtual void cacheComponentData() ;
	virtual float calcGroundFriction(struct IMobMovementProxy const &, vec3_ti const &) const ;
	virtual bool canBeBrokenFromFalling() const ;
	virtual bool canBeBuiltOver(C_BlockSource &, vec3_ti const &) const ;
	virtual bool canBeBuiltOver(C_BlockSource &, vec3_ti const &, class BlockItem const &) const ;
	virtual bool canBeFertilized(C_BlockSource &, vec3_ti const &, C_Block const &) const ;
	virtual bool canBeOriginalSurface() const ;
	virtual bool canConnect(C_Block const &, unsigned char, C_Block const &) const ;
	virtual bool canDamperVibrations() const ;
	virtual bool canHaveExtraData() const ;
	virtual bool canHurtAndBreakItem() const ;
	virtual bool canInstatick() const ;
	virtual bool canOccludeVibrations() const ;
	virtual bool canProvideFullSupport(unsigned char) const ;
	virtual bool canProvideMultifaceSupport(unsigned char) const ;
	virtual bool canProvideSupport(unsigned char, enum BlockSupportType) const ;
	virtual bool canSlide(C_BlockSource &, vec3_ti const &) const ;
	virtual bool canSurvive(C_BlockSource &, vec3_ti const &) const ;
	virtual bool causesFreezeEffect() const ;
	virtual bool checkIsPathable(C_Entity &, vec3_ti const &, vec3_ti const &) const ;
	virtual class HitResult clip(C_BlockSource const &, vec3_ti const &, vec3_t const &, vec3_t const &, bool) const ;
	virtual class HitResult clip(C_BlockSource const &, vec3_ti const &, vec3_t const &, vec3_t const &, bool, AABB const &) const ;
	virtual C_Block *copyState(C_Block const &, class ItemState const &) const ;
	virtual bool dealsContactDamage(C_Entity const &, bool) const ;
	virtual void destroy(C_BlockSource &, vec3_ti const &, C_Entity *) const ;
	virtual void entityInside(C_BlockSource &, vec3_ti const &, C_Entity &) const ;
	virtual void executeEvent(std::u8string const &, class RenderParams &) const ;
	virtual void executeItemEvent(C_ItemStack &, std::u8string const &, C_BlockSource &, vec3_ti const &, C_Entity *) const ;
	virtual bool executeTrigger(class DefinitionTrigger const &, RenderParams &) const ;
	virtual AABB *getAABB(class IConstBlockSource const &, vec3_ti const &, AABB &, bool) const ;
	virtual bool getAllowsRunes() const ;
	virtual enum BlockActorType getBlockEntityType() const ;
	virtual int getBurnOdds() const ;
	virtual bool getCollisionShape(AABB &, IConstBlockSource const &, vec3_ti const &, class optional_ref) const ;
	virtual int getColor(C_BlockSource &, vec3_ti const &) const ;
	virtual int getColor() const ;
	virtual int getComparatorSignal(C_BlockSource &, vec3_ti const &, unsigned char) const ;
	virtual void getConnectedDirections(vec3_ti const &, C_BlockSource &, bool &, bool &, bool &, bool &) const ;
	virtual enum CreativeItemCategory getCreativeCategory() const ;
	virtual class basic_string_span getCreativeGroup() const ;
	virtual void getDebugText(std::vector<std::u8string> &, vec3_ti const &) const ;
	virtual std::u8string getDescriptionId() const ;
	virtual float getDestroySpeed() const ;
	virtual int getDirectSignal(C_BlockSource &, vec3_ti const &, int) const ;
	virtual class EntityContext &getEntityForModification() const ;
	virtual float getExplosionResistance(C_Entity *) const ;
	virtual int getFlameOdds() const ;
	virtual float getFriction() const ;
	virtual bool getIgnoresDestroyPermissions(C_Entity &, vec3_ti const &) const ;
	virtual C_BlockLegacy const &getLegacyBlock() const ;
	virtual struct Brightness getLight() const ;
	virtual struct Brightness getLightEmission() const ;
	virtual MC_Color getMapColor(C_BlockSource &, vec3_ti const &) const ;
	virtual C_Material const &getMaterial() const ;
	virtual class MobSpawnerData const *getMobToSpawn(class SpawnConditions const &, C_BlockSource &) const ;
	virtual HashedString const &getName() const ;
	virtual C_Block const &getPlacementBlock(C_Entity &, vec3_ti const &, unsigned char, vec3_t const &, int) const ;
	virtual int getResourceCount(class Randomize &, int) const ;
	virtual unsigned int const &getRuntimeId() const ;
	virtual bool getSecondPart(C_BlockSource const &, vec3_ti const &, vec3_ti &) const ;
	virtual CompoundTag const &getSerializationId() const ;
	virtual ItemInstance getSilkTouchItemInstance() const ;
	virtual float getThickness() const ;
	virtual float getTranslucency() const ;
	virtual int getVariant() const ;
	virtual AABB const &getVisualShape(AABB &, bool) const ;
	virtual AABB const &getVisualShapeInWorld(C_BlockSource &, vec3_ti const &, AABB &, bool) const ;
	virtual bool hasBlockEntity() const ;
	virtual bool hasComparatorSignal() const ;
	virtual bool hasProperty(enum BlockProperty) const ;
	virtual bool hasPropertyNoLock(enum BlockProperty) const ;
	virtual bool const hasRuntimeId() const ;
	virtual bool hasState(ItemState const &) const ;
	virtual bool hasTag(HashedString const &) const ;
	virtual bool hasTag(unsigned __int64 const &) const ;
	virtual bool ignoreEntitiesOnPistonMove() const ;
	virtual void initEntity(class EntityRegistry &) ;
	virtual void initParams(RenderParams &, C_BlockSource &, vec3_ti const &, C_Entity *) const ;
	virtual bool isAir() const ;
	virtual bool isAttachedTo(C_BlockSource &, vec3_ti const &, vec3_ti &) const ;
	virtual bool isAuxValueRelevantForPicking() const ;
	virtual bool isBounceBlock() const ;
	virtual bool isButtonBlock() const ;
	virtual bool isClimbable(struct IActorMovementProxy const &) const ;
	virtual bool isContainerBlock() const ;
	virtual bool isCropBlock() const ;
	virtual bool isDoorBlock() const ;
	virtual bool isEmpty() const ;
	virtual bool isFenceBlock() const ;
	virtual bool isFenceGateBlock() const ;
	virtual bool isFilteredOut(class BlockRenderLayer) const ;
	virtual bool isHeavy() const ;
	virtual bool isInteractiveBlock() const ;
	virtual bool isLeverBlock() const ;
	virtual bool isMotionBlockingBlock() const ;
	virtual bool isMultifaceBlock() const ;
	virtual bool isObstructingChests(C_BlockSource &, vec3_ti const &) const ;
	virtual bool isPartialBlock(C_BlockSource const &, vec3_ti const &) const ;
	virtual bool isPreservingMediumWhenPlaced(C_Block const &) const ;
	virtual bool isRailBlock() const ;
	virtual bool isSignalSource() const ;
	virtual bool isSlabBlock() const ;
	virtual bool isSolid() const ;
	virtual bool isSolidBlockingBlock() const ;
	virtual bool isSolidBlockingBlockAndNotSignalSource() const ;
	virtual bool isStairBlock() const ;
	virtual bool isStandingSign() const ;
	virtual bool isStemBlock() const ;
	virtual bool isThinFenceBlock() const ;
	virtual bool isTopPartialBlock(C_BlockSource const &, vec3_ti const &) const ;
	virtual bool isUnbreakable() const ;
	virtual bool isWallBlock() const ;
	virtual bool isWaterBlocking() const ;
	virtual C_Block const &keepState(ItemState const &) const ;
	virtual bool mayConsumeFertilizer(C_BlockSource &) const ;
	virtual bool mayPick(C_BlockSource const &, bool) const ;
	virtual bool mayPick() const ;
	virtual bool mayPlace(C_BlockSource &, vec3_ti const &) const ;
	virtual bool mayPlace(C_BlockSource &, vec3_ti const &, unsigned char) const ;
	virtual bool mayPlaceOn(C_BlockSource &, vec3_ti const &) const ;
	virtual void movedByPiston(C_BlockSource &, vec3_ti const &) const ;
	virtual void neighborChanged(C_BlockSource &, vec3_ti const &, vec3_ti const &) const ;
	virtual void onExploded(C_BlockSource &, vec3_ti const &, C_Entity *) const ;
	virtual void onFallOn(C_BlockSource &, vec3_ti const &, C_Entity &, float) const ;
	virtual bool onFertilized(C_BlockSource &, vec3_ti const &, C_Entity *, enum FertilizerType) const ;
	virtual void onLightningHit(C_BlockSource &, vec3_ti const &) const ;
	virtual void onPlace(C_BlockSource &, vec3_ti const &, C_Block const &) const ;
	virtual void onPlayerPlacing(C_BlockSource &, vec3_ti const &, C_Entity &, unsigned char) const ;
	virtual void onProjectileHit(C_BlockSource &, vec3_ti const &, C_Entity const &) const ;
	virtual void onRemove(C_BlockSource &, vec3_ti const &) const ;
	virtual void onStandOn(EntityContext &, vec3_ti const &) const ;
	virtual void onStepOff(C_Entity &, vec3_ti const &) const ;
	virtual void onStepOn(C_Entity &, vec3_ti const &) const ;
	virtual void onStructureBlockPlace(C_BlockSource &, vec3_ti const &) const ;
	virtual void onStructureNeighborBlockPlace(C_BlockSource &, vec3_ti const &) const ;
	virtual void playerDestroy(C_Player &, vec3_ti const &) const ;
	virtual bool playerWillDestroy(C_Player &, vec3_ti const &) const ;
	virtual class ItemActor *popResource(C_BlockSource &, vec3_ti const &, ItemInstance const &) const ;
	virtual bool pushesOutItems() const ;
	virtual bool pushesUpFallingBlocks() const ;
	virtual void queuedTick(C_BlockSource &, vec3_ti const &, Random &) const ;
	virtual void randomTick(C_BlockSource &, vec3_ti const &, Random &) const ;
	virtual vec3_t randomlyModifyPosition(vec3_ti const &) const ;
	virtual bool shouldRandomTick() const ;
	virtual bool shouldRandomTickExtraLayer() const ;
	virtual bool shouldStopFalling(C_Entity &) const ;
	virtual void spawnResources(C_BlockSource &, vec3_ti const &, Randomize &, std::vector<C_Item const *> *, float, int) const ;
	virtual void spawnResources(C_BlockSource &, vec3_ti const &, C_Block const &, Randomize &, std::vector<C_Item const *> *, float, int, C_ItemStack const &) const ;
	virtual int telemetryVariant(C_BlockSource &, vec3_ti const &) const ;
	virtual std::u8string toDebugString() const ;
	virtual void transformOnFall(C_BlockSource &, vec3_ti const &, C_Entity *, float) const ;
	virtual void triggerEvent(C_BlockSource &, vec3_ti const &, int, int) const ;
	virtual class CopperBehavior const *tryGetCopperBehavior() const ;
	virtual C_Block const *tryGetInfested() const ;
	virtual C_Block const *tryGetUninfested() const ;
	virtual void trySpawnResourcesOnExplosion(C_BlockSource &, vec3_ti const &, C_Block const &, std::vector<C_Item const *> *, float, int) const ;
	virtual bool tryToPlace(C_BlockSource &, vec3_ti const &, struct ActorBlockSyncMessage const *) const ;
	virtual bool tryToTill(C_BlockSource &, vec3_ti const &, C_Entity &, C_ItemStack &) const ;
	virtual void updateEntityAfterFallOn(vec3_ti const &, struct UpdateEntityAfterFallOnInterface &) const ;
	virtual bool updateTallestCollisionShape(C_BlockSource const &, vec3_ti const &, AABB const &, class optional_ref, AABB &, vec3_t const &, float &) const ;
	virtual bool use(C_Player &, vec3_ti const &, unsigned char) const ;

protected:
	virtual void buildSerializationId(unsigned int) ;
	virtual void setRuntimeId(unsigned int const &) const ;

private:
	virtual bool _isSolid() const ;
	virtual class BlockTypeRegistryReadLock _lockRegistryForRead() const ;
	virtual void _tryInitEntityIfNotInitialized() ;
	virtual EntityContext const &getEntity() const ;

#endif  // 0
};

class CompoundTag;

class C_BlockActor {
private:
	virtual void destructor();
	virtual __int64 load(__int64 &, CompoundTag *, __int64 &);

public:
	virtual bool save(CompoundTag *);
};

class RayTraceResult {  // Some of these aren't set by some functions
public:
	vec3_t startPos{};
	vec3_t relativeEndPos{};
	uint32_t hitType{};  // 0 is block, 1 is actor, 3 is air
	uint32_t blockFace{};
	vec3_ti blockPos{};
	vec3_t blockHitPos{};  // If no block is found it just extends to the max ray position
	uintptr_t someActorHitPointer{};
	uintptr_t someOtherActorHitPointer{};
	uint32_t actorThingy{};  // Could contain ids or something, 0xFFFFFFFF when not facing an actor
private:
	[[maybe_unused]] uint8_t idk[0x4]{};

public:
	bool isHittingLiquid{};
	uint8_t liquidBlockFace{};  // If the liquid were a solid block, what block face would it be
private:
	[[maybe_unused]] uint8_t nothing[0x2]{};

public:
	vec3_ti liquidBlockPos{};
	vec3_t liquidBlockHitPos{};  // Full of zeroes if there is no liquid block
	bool isExtendedBlockHit{};   // Is the bedrock bridge mechanic thingy focusing a block
private:
	[[maybe_unused]] uint8_t pad[0x3]{};

public:
	RayTraceResult() = default;
};

class C_BlockSource {
public:
	C_Block *getBlock(const vec3_ti &block) const;

	C_BlockActor *getBlockEntity(const vec3_ti &block) const;

	C_Block *getLiquidBlock(const vec3_ti &block) const;

	// float getBrightness(const vec3_ti &block) const;

	void rayTraceBlocks(vec3_t &start, vec3_t &end, void *ent = nullptr);

	// bool setBlock(int, int, int, C_Block *, int, const C_Entity *);
};

class C_Player;
class C_Item;

using BlockPos = vec3_ti;